--- title: "05-编译时多态和运行时多态" created: 2025-12-02 tags: - Java --- # 编译时多态和运行时多态 ### **编译时多态和运行时多态** 编译时多态(静态多态)和运行时多态(动态多态)是面向对象编程(OOP)中多态性实现的两种不同方式,分别在编译时和运行时决定方法的绑定。两者的实现方式、适用场景和特点有所不同。 ### **1. 编译时多态(Compile-time Polymorphism)** 编译时多态,也叫静态多态,是在编译阶段决定方法的调用。编译时多态主要通过**方法重载(Method Overloading)**来实现。 #### **方法重载(Method Overloading)**: 方法重载是指在同一个类中定义多个方法,这些方法具有相同的方法名,但参数列表不同(参数的类型或数量不同)。Java 编译器根据方法调用时传入的参数类型和数量,在编译阶段决定调用哪个重载方法。 - **特点**: - 方法名相同,但参数不同(可以是数量、类型或顺序的变化)。 - 编译时根据传入参数类型选择匹配的方法。 - 重载方法的返回类型不影响重载的决策。 #### **示例代码:** ```java class Example { void display(int a) { System.out.println("Integer: " + a); } void display(double a) { System.out.println("Double: " + a); } void display(String a) { System.out.println("String: " + a); } } public class Main { public static void main(String[] args) { Example obj = new Example(); obj.display(5); // 调用 display(int a) obj.display(3.14); // 调用 display(double a) obj.display("Hello"); // 调用 display(String a) } } ``` - **解释**:在上面的代码中,`display()` 方法被重载了三次,分别处理不同类型的参数(`int`、`double` 和 `String`)。编译器会在编译时根据参数的类型来决定调用哪个版本的 `display()` 方法。 #### **编译时多态的优势**: - **高效**:编译器能够在编译阶段确定调用的方法,因此在运行时没有额外的开销。 - **类型安全**:由于编译时就确定了方法的调用,避免了运行时类型错误。 --- ### **2. 运行时多态(Runtime Polymorphism)** 运行时多态,也叫动态多态,是在程序运行时决定方法的调用。运行时多态通常是通过**方法重写(Method Overriding)**来实现。 #### **方法重写(Method Overriding)**: 方法重写是子类重新定义父类中已有的方法,并提供不同的实现。当通过父类引用调用方法时,实际执行的是子类重写后的方法。此时方法的绑定是根据对象的实际类型,而不是引用类型来决定的。方法重写是实现运行时多态的关键。 - **特点**: - 子类重写父类的方法,方法名和参数列表必须相同。 - 运行时根据对象的实际类型来决定调用哪个方法。 - 可以通过父类引用指向子类对象,表现出不同的行为。 #### **示例代码:** ```java class Animal { void sound() { System.out.println("Animal makes a sound"); } } class Dog extends Animal { @Override void sound() { System.out.println("Dog barks"); } } class Cat extends Animal { @Override void sound() { System.out.println("Cat meows"); } } public class Main { public static void main(String[] args) { Animal myDog = new Dog(); // Animal reference but Dog object Animal myCat = new Cat(); // Animal reference but Cat object myDog.sound(); // 输出: Dog barks myCat.sound(); // 输出: Cat meows } } ``` - **解释**:在这个例子中,`Animal` 是父类,`Dog` 和 `Cat` 是子类。尽管 `myDog` 和 `myCat` 都是 `Animal` 类型的引用,但它们分别指向 `Dog` 和 `Cat` 对象。在调用 `sound()` 方法时,实际执行的是子类重写后的方法。 #### **运行时多态的优势**: - **灵活性和可扩展性**:通过父类类型的引用可以调用不同子类的实现,使得代码具有更高的灵活性和可扩展性。 - **实现多态性**:运行时多态允许在程序运行时决定对象的行为,这使得程序能够根据不同的对象表现出不同的行为。 --- ### **总结:编译时多态与运行时多态的区别** | **特点** | **编译时多态(静态多态)** | **运行时多态(动态多态)** | | --- | --- | --- | | **实现方式** | 方法重载(Method Overloading) | 方法重写(Method Overriding) | | **方法绑定时机** | 编译时 | 运行时 | | **决策依据** | 方法名相同,参数列表不同 | 方法名和参数列表相同,依据对象的实际类型 | | **多态类型** | 静态多态,方法的调用在编译时就确定 | 动态多态,方法的调用在运行时决定 | | **类型** | 方法签名不同(参数不同) | 子类重写父类方法 | | **调用机制** | 根据方法参数类型选择正确的方法 | 根据实际对象类型选择调用的重写方法 | | **优点** | 性能较高,编译时就能确定调用方法 | 提高了灵活性和可扩展性,支持多态性 | ## 相关笔记 多态的载体是方法重写,完整规则见 [[04-重写与重载|重写与重载]];多态在本篇讲"绑定时机",[[01-继承与多态|继承与多态]] 讲"整体图景",三篇互补。 --- ⬅️ [[04-方法重载和方法重写|方法重载和方法重写]] 🏠 [[00-Java|00-Java]] ➡️ [[06-访问控制修饰符|访问控制修饰符]]